#include "server.h"

//////////////////////////////////////////////
/// HTTP 服务器
//////////////////////////////////////////////

HttpServer* HttpServer::instance = nullptr;

HttpServer *HttpServer::getInstance()
{
    if(instance == nullptr) {
        instance = new HttpServer();
    }
    return instance;
}

void HttpServer::init()
{
    // configure routing
    httpServer.route("/ping", [](){
        qDebug() << "[http server] receive ping request";
        return "pong";
    });

    httpServer.route("/service/user/get_user_info", [=](const QHttpServerRequest& req){
        return this->getUserInfo(req);
    });

    httpServer.route("/service/friend/get_friend_list", [=](const QHttpServerRequest& req){
        return this->getFriendList(req);
    });

    httpServer.route("/service/friend/get_chat_session_list", [=](const QHttpServerRequest& req){
        return this->getChatSessionList(req);
    });

    httpServer.route("/service/friend/get_pending_friend_events", [=](const QHttpServerRequest& req){
        return this->getApplyList(req);
    });

    httpServer.route("/service/message_storage/get_recent", [=](const QHttpServerRequest& req){
        return this->getRecentMessage(req);
    });

    httpServer.route("/service/message_transmit/new_message", [=](const QHttpServerRequest& req){
        return this->getNewMessage(req);
    });

    httpServer.route("/service/user/set_nickname", [=](const QHttpServerRequest& req){
        return this->getNickname(req);
    });

    httpServer.route("/service/user/set_description", [=](const QHttpServerRequest& req){
        return this->getDescription(req);
    });

    httpServer.route("/service/user/get_phone_verify_code", [=](const QHttpServerRequest& req){
        return this->getVerifyCode(req);
    });

    httpServer.route("/service/user/set_phone", [=](const QHttpServerRequest& req){
        return this->getPhone(req);
    });

    httpServer.route("/service/user/set_avatar", [=](const QHttpServerRequest& req){
        return this->getAvatar(req);
    });

    httpServer.route("/service/friend/remove_friend", [=](const QHttpServerRequest& req){
        return this->deleteFriend(req);
    });

    httpServer.route("/service/friend/add_friend_apply", [=](const QHttpServerRequest& req){
        return this->addFriendApply(req);
    });

    httpServer.route("/service/friend/add_friend_process", [=](const QHttpServerRequest& req){
        return this->addFriendProcess(req);
    });

    httpServer.route("/service/friend/create_chat_session", [=](const QHttpServerRequest& req){
        return this->createChatSession(req);
    });

    auto tcpServer = std::make_unique<QTcpServer>();
    if(!tcpServer->listen(QHostAddress::Any, 8000)) {
        LOG() << "listen failed";
        return;
    }
    if (!httpServer.bind(tcpServer.get())) {
        LOG() << "bind failed";
        return;
    }

    // QHttpServer 接管 socket
    tcpServer.release();

    LOG() << "http server start success";
}

QHttpServerResponse HttpServer::getUserInfo(const QHttpServerRequest &req)
{
    QByteArray body = req.body();
    bite_im::GetUserInfoReq pbReq;
    pbReq.deserialize(&serializer, body);
    LOG() << "[http server] receive getUserInfo request: " << pbReq.requestId();

    bite_im::UserInfo userInfo;
    userInfo.setUserId("1000");
    userInfo.setNickname("luffy");
    userInfo.setDescription("become the pirate king");
    userInfo.setPhone("15912345678");
    userInfo.setAvatar(readByteArrayFromFile(":/resource/image/luffy.png"));

    bite_im::GetUserInfoRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");
    pbRsp.setUserInfo(userInfo);

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getFriendList(const QHttpServerRequest &req)
{
    bite_im::GetFriendListReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive getFriendList request: " << pbReq.requestId();

    QList<bite_im::UserInfo> list;
    for(int i = 0;i < 20;i ++) {
        bite_im::UserInfo userInfo = makeUserInfo(i);
        list.push_back(userInfo);
    }

    bite_im::GetFriendListRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");
    pbRsp.setFriendList(list);

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getChatSessionList(const QHttpServerRequest &req)
{
    bite_im::GetChatSessionListReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive getChatSessionList request: " << pbReq.requestId();

    QList<bite_im::ChatSessionInfo> list;
    for(int i = 0;i < 20;i ++) {
        list.push_back(makeChatSessionInfo(i));
    }

    bite_im::ChatSessionInfo groupInfo;
    groupInfo.setChatSessionId(QString::number(3000));
    groupInfo.setChatSessionName("session" + QString::number(3000));
    groupInfo.setAvatar(readByteArrayFromFile(":/resource/image/group.png"));
    groupInfo.setPrevMessage(makeMessageInfo("1234"));
    groupInfo.setSingleChatFriendId("");
    list.push_back(groupInfo);

    bite_im::GetChatSessionListRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");
    pbRsp.setChatSessionInfoList(list);

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getApplyList(const QHttpServerRequest &req)
{
    bite_im::GetPendingFriendEventListReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive getApplyList request: " << pbReq.requestId();

    QList<bite_im::FriendEvent> list;
    for(int i = 0;i < 20;i ++) {
        bite_im::FriendEvent friendApply;
        friendApply.setSender(makeUserInfo(i + 20));
        list.push_back(friendApply);
    }

    bite_im::GetPendingFriendEventListRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");
    pbRsp.setEvent(list);

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getRecentMessage(const QHttpServerRequest &req)
{
    bite_im::GetRecentMsgReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive getRecentMsg request: " << pbReq.requestId()
          << ", chatSessionId " << pbReq.chatSessionId();

    QList<bite_im::MessageInfo> list;
    for(int i = 0;i < 20;i ++) {
        list.push_back(makeMessageInfo(pbReq.chatSessionId()));
    }

    bite_im::GetRecentMsgRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");
    pbRsp.setMsgList(list);

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getNewMessage(const QHttpServerRequest &req)
{
    bite_im::NewMessageReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive sendMessage request: " << pbReq.requestId()
          << ", loginSessionId " << pbReq.sessionId()
          << ", chatSessionId " << pbReq.chatSessionId();

    bite_im::NewMessageRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getNickname(const QHttpServerRequest &req)
{
    bite_im::SetUserNicknameReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive setUserNickname request: " << pbReq.requestId();

    bite_im::SetUserNicknameRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getDescription(const QHttpServerRequest &req)
{
    bite_im::SetUserDescriptionReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive setUserDescription request: " << pbReq.requestId();

    bite_im::SetUserDescriptionRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getVerifyCode(const QHttpServerRequest &req)
{
    bite_im::PhoneVerifyCodeReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive getVerifyCode request: " << pbReq.requestId();

    bite_im::PhoneVerifyCodeRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setVerifyCodeId("textVerifyCodeId");
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getPhone(const QHttpServerRequest &req)
{
    bite_im::SetUserPhoneNumberReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive modifyPhone request: " << pbReq.requestId();

    bite_im::SetUserPhoneNumberRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::getAvatar(const QHttpServerRequest &req)
{
    bite_im::SetUserAvatarReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive modifyAvatar request: " << pbReq.requestId();

    bite_im::SetUserAvatarRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::deleteFriend(const QHttpServerRequest &req)
{
    bite_im::FriendRemoveReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive deleteFriend request: " << pbReq.requestId();

    bite_im::FriendRemoveRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::addFriendApply(const QHttpServerRequest &req)
{
    bite_im::FriendAddReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive sendFriendApply request: " << pbReq.requestId();

    bite_im::FriendAddRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::addFriendProcess(const QHttpServerRequest &req)
{
    bite_im::FriendAddProcessReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive addFriendProcess request: " << pbReq.requestId();

    bite_im::FriendAddProcessRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

QHttpServerResponse HttpServer::createChatSession(const QHttpServerRequest &req)
{
    bite_im::ChatSessionCreateReq pbReq;
    pbReq.deserialize(&serializer, req.body());
    LOG() << "[http server] receive createChatSession request: " << pbReq.requestId()
          << pbReq.memberIdList();

    bite_im::ChatSessionCreateRsp pbRsp;
    pbRsp.setRequestId(pbReq.requestId());
    pbRsp.setSuccess(true);
    pbRsp.setErrmsg("");

    QHttpServerResponse rsp("application/x-protobuf", pbRsp.serialize(&serializer));
    return rsp;
}

HttpServer::HttpServer()
{
}

//////////////////////////////////////////////
/// Websocket 服务器
//////////////////////////////////////////////

WebsocketServer* WebsocketServer::instance = nullptr;

WebsocketServer *WebsocketServer::getInstance()
{
    if(instance == nullptr) {
        instance = new WebsocketServer();
    }
    return instance;
}

WebsocketServer::WebsocketServer()
    :wsServer("websocket server", QWebSocketServer::NonSecureMode)
{
}

bool WebsocketServer::init()
{
    // 1. connect signal and slot
    connect(&wsServer, &QWebSocketServer::newConnection, this, [=](){
        qDebug() << "[Websocket server] connection established successfully";

        QWebSocket* socket = wsServer.nextPendingConnection();

        connect(socket, &QWebSocket::disconnected, this, [=](){
            qDebug() << "[Websocket server] connection disconnect";

            disconnect(this, &WebsocketServer::sendMessageToClient, this, nullptr);
            disconnect(this, &WebsocketServer::sendDeleteFriendToClient, this, nullptr);
            disconnect(this, &WebsocketServer::sendFriendApplyToClient, this, nullptr);
            disconnect(this, &WebsocketServer::agreeFriendApplyToClient, this, nullptr);
        });

        connect(socket, &QWebSocket::errorOccurred, this, [=](const QAbstractSocket::SocketError& error){
            qDebug() << "[Websocket server] connection error" << error;
        });

        connect(socket, &QWebSocket::textMessageReceived, this, [=](const QString& msg){
            qDebug() << "[Websocket server] receive text msg: " << msg;
        });

        connect(socket, &QWebSocket::binaryMessageReceived, this, [=](const QByteArray& msg){
            qDebug() << "[Websocket server] receive binary msg " << msg;
        });

        connect(this, &WebsocketServer::sendMessageToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::MessageInfo info = makeMessageInfo("1236");

            bite_im::NotifyNewMessage newMsg;
            newMsg.setMessageInfo(info);

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::CHAT_MESSAGE_NOTIFY);
            notifyMsg.setNewMessageInfo(newMsg);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });

        connect(this, &WebsocketServer::sendDeleteFriendToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::NotifyFriendRemove friendRemove;
            friendRemove.setUserId("1234");

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY);
            notifyMsg.setFriendRemove(friendRemove);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });

        connect(this, &WebsocketServer::sendFriendApplyToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::NotifyFriendAddApply friendApply;
            friendApply.setUserInfo(makeUserInfo(100));

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY);
            notifyMsg.setFriendAddApply(friendApply);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });

        connect(this, &WebsocketServer::agreeFriendApplyToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::NotifyFriendAddProcess process;
            process.setAgree(true);
            process.setUserInfo(makeUserInfo(1000));

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
            notifyMsg.setFriendProcessResult(process);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });

        connect(this, &WebsocketServer::rejectFriendApplyToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::NotifyFriendAddProcess process;
            process.setAgree(false);
            process.setUserInfo(makeUserInfo(1000));

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
            notifyMsg.setFriendProcessResult(process);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });

        connect(this, &WebsocketServer::createChatSessionToClient, this, [=](){
            if(socket == nullptr || !socket->isValid()) {
                LOG() << "connect has error";
                return;
            }

            bite_im::ChatSessionInfo info;
            info.setChatSessionId("3000");
            info.setChatSessionName("new group chat");
            info.setSingleChatFriendId("");
            info.setAvatar(readByteArrayFromFile(":/resource/image/group.png"));
            info.setPrevMessage(makeMessageInfo("3000"));

            bite_im::NotifyNewChatSession newSession;
            newSession.setChatSessionInfo(info);

            bite_im::NotifyMessage notifyMsg;
            notifyMsg.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY);
            notifyMsg.setNewChatSessionInfo(newSession);

            socket->sendBinaryMessage(notifyMsg.serialize(&serializer));
        });
    });

    // 2. bind port, start server
    bool ok = wsServer.listen(QHostAddress::Any, 8001);
    return ok;
}
